/**
 * chinagoods.com
 * Copyright (c) 2020-2024 All Rights Reserved.
 */
package com.ruoyi.system.biz.impl;

import cn.hutool.core.util.StrUtil;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.exception.BusiException;
import com.ruoyi.system.biz.CashBizService;
import com.ruoyi.system.domain.Cash;
import com.ruoyi.system.domain.CashHistory;
import com.ruoyi.system.domain.UserRate;
import com.ruoyi.system.dto.TransferSubmitDto;
import com.ruoyi.system.service.CashHistoryService;
import com.ruoyi.system.service.CashService;
import com.ruoyi.system.service.ISysUserService;
import com.ruoyi.system.service.UserRateService;
import com.ruoyi.system.vo.MemberVo;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author yangpeng
 * Created by on 2024-01-30 13:04
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class CashBizServiceImpl extends BaseBizServiceImpl implements CashBizService {

    final private RedissonClient redissonClient;
    final private CashService cashService;
    final private CashHistoryService cashHistoryService;
    final private ISysUserService userService;
    final private UserRateService userRateService;

    @Override
    public synchronized void transfer(SysUser sendUser, TransferSubmitDto dto) {
        Long userId = sendUser.getUserId();

        SysUser user = userService.getByUserName(dto.getUsername());
        if (user == null) {
            throw new BusiException("对方账号不存在");
        }
        Long receiveId = user.getUserId();
        Cash cash = this.getByUserId(userId);
        if (cash.getEarning().compareTo(dto.getMoney()) < 0) {
            throw new BusiException("余额不足");
        }
        CashHistory userCashHis = new CashHistory(userId, dto.getMoney(), "reduce", "转账至:" + dto.getUsername(),
                "transfer");
        userCashHis.setSource("user");
        this.updateCash(userId, userCashHis);


        CashHistory receiveUserCashHis = new CashHistory(receiveId, dto.getMoney(), "add", "接收(" + sendUser.getUserName() + ")转账",
                "transfer");
        receiveUserCashHis.setSource("user");
        this.updateCash(receiveId, receiveUserCashHis);

    }

    @Override
    public Cash getByUserId(Long userId) {
        SysUser user = userService.check(userId);

        Cash cash = new Cash();
        cash.setUserId(userId);
        cash = cashService.getDomain(cash);
        if (cash == null) {
            cash = new Cash();
            cash.setEarning(BigDecimal.ZERO);

            cash.setMemberEarning(BigDecimal.ZERO);
            cash.setPersonEarning(BigDecimal.ZERO);
            cash.setUserId(userId);
            cash.setUsername(user.getUserName());
            cashService.addDomain(cash);
        }
        return cash;
    }

    @Override
    @Transactional
    public void benefit(Long userId, String orderNo, BigDecimal userEarning, String type, String channelCode) {
        //查出上级  计算推广收益
        List<MemberVo> list = userService.findParents(userId, 3);
        List<MemberVo> parents = list.stream().map(p -> {
            //获取当前通道的费率
            UserRate userRate = userRateService.getUserRate(p.getUserId(), channelCode);
            //
            if (userRate == null) {
                log.info("缺少费率,userid={}", p.getUserId());
                return null;
            }

            p.setRate(userRate.getRate());

            return p;
        }).collect(Collectors.toList());

        for (int i = 0; i < parents.size(); i++) {
            MemberVo memberVo = parents.get(i);
            if (memberVo == null) {
                continue;
            }
            //查询
            if (i == 0) {//自身收益
                BigDecimal changeMoney = userEarning.multiply(memberVo.getRate().divide(new BigDecimal(100)));
                CashHistory cashHistory = new CashHistory(memberVo.getUserId(), changeMoney, "add", "订单收益", "earning");
                cashHistory.setOrderNo(orderNo);
                this.updateCash(cashHistory);
            } else if (i != parents.size() - 1) {
                this.parentCash(parents.get(i - 1), parents.get(i), userEarning, orderNo);
            }

        }

    }

    //推广收益
    private void parentCash(MemberVo user, MemberVo parent, BigDecimal totalPrice, String orderNo) {
        BigDecimal rate = parent.getRate().subtract(user.getRate());
        if (rate.compareTo(BigDecimal.ZERO) <= 0) {
            // log.info("上级用户id:{}，费率{}，比下级用户id：{}，费率{}小，无法获得推荐收益", parent.getUserId(), parent.getRate(), user.getUserId(), user.getRate());
            return;
        }
        BigDecimal changeMoney = totalPrice.multiply(rate.divide(new BigDecimal(100)));
        CashHistory cashHistory = new CashHistory(parent.getUserId(), changeMoney, "add", "下级贡献收益", "earning");
        cashHistory.setOrderNo(orderNo);
        this.updateCash(cashHistory);

    }

    @Override
    @Transactional
    public void updateCash(CashHistory cashHistory) {

        updateCash(cashHistory.getUserId(), cashHistory);
    }

    @Override
    public void updateCash(Long userId, CashHistory cashHistory) {

        RLock lock = redissonClient.getLock("rock_update_cash:" + userId); // 创建分布式锁对象

        try {
            lock.lock(); // 获取锁
            // 执行业务操作...
            excute(cashHistory);
        } finally {
            lock.unlock(); // 释放锁
        }
    }

    @Override
    public void updateCashLock(CashHistory cashHistory) {

        RLock lock = redissonClient.getLock("rock_update_cash:" + cashHistory.getUserId()); // 创建分布式锁对象

        try {
            lock.lock(); // 获取锁
            // 执行业务操作...
            excute(cashHistory);
        } finally {
            lock.unlock(); // 释放锁
        }
    }


    /**
     * 更新用户余额
     *
     * @param obj
     */

    protected void excute(Object obj) {
        CashHistory cashHistory = (CashHistory) obj;
        Long userId = cashHistory.getUserId();
        try {
            BigDecimal total = cashHistory.getChangeMoney();
            BigDecimal changeMoney;
            BigDecimal earning = null;
            Cash cash = cashService.getByUserId(userId);
            if (StrUtil.equals(cashHistory.getChangeType(), "reduce")) {
                changeMoney = BigDecimal.ZERO.subtract(cashHistory.getChangeMoney());
            } else {
                changeMoney = cashHistory.getChangeMoney();
            }

            String type = cashHistory.getType();
            cash.setEarning(cash.getEarning().add(changeMoney));

            if (StrUtil.equals(type, "freeze")) {//资产冻结
                cash.setFreezeEarning(cash.getFreezeEarning().add(cashHistory.getChangeMoney()));

            } else if (StrUtil.equals(type, "member")) {//团队收益
                cash.setMemberEarning(cash.getMemberEarning().add(cashHistory.getChangeMoney()));
                cashHistory.setType("recommend");
            } else if (StrUtil.equals(type, "person")) {//个人收益
                cash.setPersonEarning(cash.getPersonEarning().add(cashHistory.getChangeMoney()));

            }
            if (cash.getEarning().compareTo(BigDecimal.ZERO) < 0) {
                throw new BusiException("金额不足");
            }
            cashService.updateDomain(cash);
            earning = cash.getEarning();
            cashHistory.setEarning(earning);
            cashHistoryService.addDomain(cashHistory);
        } catch (Exception e) {
            if (e instanceof DuplicateKeyException) {
                DuplicateKeyException duplicateKeyException = (DuplicateKeyException) e;
                throw duplicateKeyException;
            } else {
                log.info("更新账户发生异常发生异常:{}", e.getMessage());
            }
            throw new BusiException("更新金额异常");
        }

    }

}

